/*
 * @Author: Damon Liu
 * @Date: 2024-11-21 00:48:36
 * @LastEditors: Damon Liu
 * @LastEditTime: 2025-04-30 17:33:12
 * @Description: electron 主程序应用
 */
import { app, BrowserWindow, Menu, ipcMain, Tray, shell, dialog, session, Notification } from 'electron'
import { createRequire } from 'node:module'
import { fileURLToPath } from 'node:url'
import path from 'node:path'
import store from './store';
import { exec } from 'node:child_process';
import AutoLaunch from 'auto-launch';
import { existsSync } from 'node:fs';
import express from 'express'
import cors from 'cors'
import bodyParser from 'body-parser'
import schedule from 'node-schedule'
import { expandRecurringSchedules } from './tool'
import dayjs from 'dayjs'

const createShortcut = () => {

}

const require = createRequire(import.meta.url)

const __dirname = path.dirname(fileURLToPath(import.meta.url));   // 当前路径

console.log('开始运行')


// The built directory structure
//
// ├─┬─┬ dist
// │ │ └── index.html
// │ │
// │ ├─┬ dist-electron
// │ │ ├── main.js
// │ │ └── preload.mjs
// │
process.env.APP_ROOT = path.join(__dirname, '..')   // APP 根目录

// 🚧 Use ['ENV_NAME'] avoid vite:define plugin - Vite@2.x
export const VITE_DEV_SERVER_URL = process.env['VITE_DEV_SERVER_URL']   // VITE 运行地址
export const MAIN_DIST = path.join(process.env.APP_ROOT, 'dist-electron') // 正式环境electron目录
export const RENDERER_DIST = path.join(process.env.APP_ROOT, 'dist')  // 正式环境打包目录

process.env.VITE_PUBLIC = VITE_DEV_SERVER_URL ? path.join(process.env.APP_ROOT, 'public') : RENDERER_DIST

let win;    // 主应用窗口

let winSession;   // 主窗口应用的session

let settingWindow;  // 基础设置

let tray;   // 系统托盘

let scheduleWindow = null;  // 添加全局变量

// 正式环境启动处理开机自启动问题
if (!VITE_DEV_SERVER_URL) {
  const minecraftAutoLauncher = new AutoLaunch({
    name: '日程表',
    path: app.getPath('exe'),
  });
  minecraftAutoLauncher.enable();

  //minecraftAutoLauncher.disable();


  minecraftAutoLauncher.isEnabled()
    .then(function (isEnabled) {
      if (isEnabled) {
        return;
      }
      minecraftAutoLauncher.enable();
    })
    .catch(function (err) {
      // handle error
    });
}


// 当桌面不存在快捷方程式的时候创建
const makeShortcutWhenNotExist = async () => {
  if (!VITE_DEV_SERVER_URL) {
    const appName = app.getName();
    const shortcutPath = path.join(app.getPath('desktop'), `${appName}.lnk`);
    if (!existsSync(shortcutPath)) {
      createShortcut(app.getName(), {
        target: app.getPath('exe'),
        icon: app.getPath('exe')
      });
    }
  }
}

// 应用的ico路径
const iconPath = path.join(process.env.APP_ROOT, 'logo.ico')

// 获取托盘图标右键菜单
const getTaryMenu = async () => {
  const minecraftAutoLauncher = new AutoLaunch({
    name: '日程表',
    path: app.getPath('exe'),
  });

  const isEnabled = await minecraftAutoLauncher.isEnabled();
  const contextMenu = Menu.buildFromTemplate([
    {
      label: '基础设置', click: () => {
        createSettingWindow();
      }
    },
    {
      label: '打开开发者工具', click: () => {
        win.openDevTools()
      }
    },
    {
      label: isEnabled ? '禁止开机启动' : '申请开机启动',
      click: () => {
        if (isEnabled) {
          minecraftAutoLauncher.disable();
          dialog.showMessageBox({
            type: 'info',
            title: '提示',
            message: '已关闭开机自启动'
          })
        }
        else {
          minecraftAutoLauncher.enable();
          dialog.showMessageBox({
            type: 'info',
            title: '提示',
            message: '已开启开机自启动（可能需要用户手动允许）'
          })
        }
        getTaryMenu()
      }
    },
    {
      label: '打开开机启动目录',
      click: () => {
        exec('explorer shell:Common Startup', (error, stdout, stderr) => {
          if (error) {
            console.error(`执行出错: ${error}`);
            return;
          }
          else {
            //(new Notification('打开开机启动目录成功')).show()
          }
          console.log(`stdout: ${stdout}`);
          console.error(`stderr: ${stderr}`);
        })
      }
    },
    {
      label: '打开日程表', click: () => {
        if (scheduleWindow) {
          if (scheduleWindow.isVisible()) {
            scheduleWindow.hide();
          } else {
            scheduleWindow.show();
          }
        } else {
          createScheduleWindow();
        }
      }
    },
    {
      label: '打开程序目录', click: () => {
        const shortcutPath = path.join(app.getPath('exe'), `../${app.getName()}.lnk`);
        if (!existsSync(shortcutPath)) {
          createShortcut(path.join(app.getPath('exe'), `../${app.getName()}.lnk`), {
            target: app.getPath('exe'),
            icon: app.getPath('exe')
          })
        }
        shell.showItemInFolder(app.getPath('exe'))
      }
    },
    {
      label: '重启应用', click: () => {
        app.relaunch();
        app.exit(0)
      }
    },
    { label: '退出', click: () => app.quit() }
  ])
  
  // 添加托盘点击事件
  tray.on('click', () => {
    if (scheduleWindow) {
      if (scheduleWindow.isVisible()) {
        scheduleWindow.hide();
      } else {
        scheduleWindow.show();
      }
    } else {
      createScheduleWindow();
    }
  });

  tray.setToolTip('日程表')
  tray.setContextMenu(contextMenu);
}

// 创建基础设置窗口
const createSettingWindow = () => {
  settingWindow = new BrowserWindow({
    icon: path.join(process.env.APP_ROOT, 'logo.ico'),
    title: '基本设置',
    webPreferences: {
      nodeIntegration: true,
      contextIsolation: true,
      preload: path.join(__dirname, 'preload.js'),
    },
    width: 650,
    height: 660,
    show: false,
    //skipTaskbar: true,
    autoHideMenuBar: true,
    //maximizable: false
  })
  settingWindow.once('ready-to-show', () => {
    settingWindow.show()
  })
  settingWindow.webContents.on('did-finish-load', () => {
    settingWindow.webContents.send('navigate-to', 'baseSettingIndex')
  })
  const pageUrl = '/#/baseSettingIndex';

  if (VITE_DEV_SERVER_URL) {
    //settingWindow.loadURL(`${VITE_DEV_SERVER_URL}${pageUrl}`)
    settingWindow.loadURL(VITE_DEV_SERVER_URL);
    //settingWindow.webContents.openDevTools()
  } else {
    settingWindow.loadFile(`${path.join(RENDERER_DIST, 'index.html')}`)
  }
  //settingWindow.webContents.openDevTools()
}

// 创建日程表窗口
const createScheduleWindow = () => {
  if (scheduleWindow) {
    scheduleWindow.focus();
    return;
  }

  scheduleWindow = new BrowserWindow({
    icon: path.join(process.env.APP_ROOT, 'logo.ico'),
    title: '日程表',
    webPreferences: {
      nodeIntegration: true,
      contextIsolation: true,
      preload: path.join(__dirname, 'preload.js'),
    },
    width: 1400,
    height: 800,
    show: false,
    autoHideMenuBar: true,
    resizable: true,
    minimizable: true,
    maximizable: true,
    title: '日程表'
  })

  scheduleWindow.once('ready-to-show', () => {
    scheduleWindow.show()
  })

  scheduleWindow.webContents.on('did-finish-load', () => {
    scheduleWindow.webContents.send('navigate-to', 'schedule')
  })

  if (VITE_DEV_SERVER_URL) {
    scheduleWindow.loadURL(VITE_DEV_SERVER_URL)
    scheduleWindow.webContents.openDevTools()
  } else {
    scheduleWindow.loadFile(`${path.join(RENDERER_DIST, 'index.html')}`)
  }

  // 监听窗口关闭事件
  scheduleWindow.on('closed', () => {
    scheduleWindow = null
  })
}

// Quit when all windows are closed, except on macOS. There, it's common
// for applications and their menu bar to stay active until the user quits
// explicitly with Cmd + Q.
/* app.on('window-all-closed', () => {
  if (process.platform !== 'darwin') {
    app.quit()
    win = null
  }
}) */

app.on('activate', () => {
  // On OS X it's common to re-create a window in the app when the
  // dock icon is clicked and there are no other windows open.
  if (BrowserWindow.getAllWindows().length === 0) {
    createWindow()
  }
})

// 当开始的时候
app.whenReady().then(() => {
  tray = new Tray(path.join(process.env.APP_ROOT, 'logo.ico'));
  getTaryMenu();
  makeShortcutWhenNotExist();
  checkTodayReminders();
  /* // 每天凌晨检查新的提醒
  schedule.scheduleJob('0 0 * * *', () => {
    checkTodayReminders()
  }) */
  // 每天晚上 23:59 更新第二天的日程
  schedule.scheduleJob('59 23 * * *', () => {
    checkTomorrowReminders();
  });

  // 根据起始日期获取周日程
  ipcMain.handle('getWeekSchedules', async (event, weekStart) => {
    const schedules = store.get('scheduleList', [])
    // 1. 解析传入日期
    const date = weekStart ? new Date(weekStart) : new Date()
    // 2. 计算本周一
    const monday = new Date(date)
    monday.setHours(0, 0, 0, 0)
    // 3. 计算本周日
    const sunday = new Date(monday)
    sunday.setDate(monday.getDate() + 6)
    sunday.setHours(23, 59, 59, 999)

    const weekSchedules = expandRecurringSchedules(schedules, monday, sunday).filter(schedule => {
      const scheduleDate = new Date(schedule.start)
      return scheduleDate >= monday && scheduleDate <= sunday
    })

    /* const expandedSchedules = expandRecurringSchedules(weekSchedules, startDate, endDate) */
    console.log({
      weekSchedules
    })
    return {
      schedules: weekSchedules,
      weekInfo: {
        start: monday.toISOString(),
        end: sunday.toISOString(),
        count: weekSchedules.length
      }
    }
  })

  // 获取所有日程
  ipcMain.handle('getSchedules', () => {
    return store.get('scheduleList', [])
  })

  // 创建日程
  ipcMain.handle('createSchedule', async (event, schedule) => {
    const schedules = store.get('scheduleList', [])
    const newSchedule = {
      ...schedule,
      id: Date.now().toString(),
      hasNotified: false
    }
    schedules.push(newSchedule)
    store.set('scheduleList', schedules)

    // 如果是今天的日程且有提醒时间，则创建提醒任务
    if (newSchedule.reminder) {
      checkSingleReminder(newSchedule)
    }

    return newSchedule
  })
  // 打开日程窗口
  ipcMain.handle('openScheduleWindow', () => {
    createScheduleWindow();
  })

  // 获取每日日程
  ipcMain.handle('getDailySchedules', async (event, dateStr) => {
    const schedules = store.get('scheduleList', [])
    const date = dateStr ? new Date(dateStr) : new Date()
    const dayStart = new Date(date)
    dayStart.setHours(0, 0, 0, 0)
    const dayEnd = new Date(dayStart)
    dayEnd.setDate(dayEnd.getDate() + 1)
    dayEnd.setMilliseconds(dayEnd.getMilliseconds() - 1)

    const dailySchedules = expandRecurringSchedules(schedules, dayStart, dayEnd).filter(schedule => {
      const scheduleDate = new Date(schedule.start)
      return scheduleDate >= dayStart && scheduleDate <= dayEnd
    })

    return {
      schedules: dailySchedules,
      dayInfo: {
        date: dayStart.toISOString(),
        count: dailySchedules.length
      }
    }
  })
})

// 创建 Express 服务
const expressApp = express()
const PORT = 3001

// 中间件
expressApp.use(cors())
expressApp.use(express.json())

// 获取所有日程
expressApp.get('/api/schedules', (req, res) => {
  const schedules = store.get('scheduleList', [])
  res.json(schedules)
})

// 根据时间范围获取日程
expressApp.get('/api/schedules/range', (req, res) => {
  try {
    const { start, end } = req.query;
    
    if (!start || !end) {
      return res.status(400).json({ 
        error: '请提供开始时间(start)和结束时间(end)参数' 
      });
    }

    // 验证日期格式 YYYY-MM-DD HH:mm:ss
    const dateFormatRegex = /^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/;
    if (!dateFormatRegex.test(start) || !dateFormatRegex.test(end)) {
      return res.status(400).json({ 
        error: '日期格式无效，请使用 YYYY-MM-DD HH:mm:ss 格式' 
      });
    }

    const startDate = new Date(start.replace(' ', 'T'));
    const endDate = new Date(end.replace(' ', 'T'));

    if (isNaN(startDate.getTime()) || isNaN(endDate.getTime())) {
      return res.status(400).json({ 
        error: '无效的日期值' 
      });
    }

    const schedules = store.get('scheduleList', []);
    const rangeSchedules = expandRecurringSchedules(schedules, startDate, endDate)
      .filter(schedule => {
        const scheduleDate = new Date(schedule.start);
        return scheduleDate >= startDate && scheduleDate <= endDate;
      });

    // 格式化返回的日期为 YYYY-MM-DD HH:mm:ss
    const formatDate = (date) => {
      const pad = (num) => String(num).padStart(2, '0');
      return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}`;
    };

    res.json({
      schedules: rangeSchedules.map(schedule => ({
        ...schedule,
        start: formatDate(new Date(schedule.start)),
        end: formatDate(new Date(schedule.end)),
        reminder: schedule.reminder ? formatDate(new Date(schedule.reminder)) : null
      })),
      rangeInfo: {
        start: formatDate(startDate),
        end: formatDate(endDate),
        count: rangeSchedules.length
      }
    });
  } catch (error) {
    res.status(500).json({ 
      error: '服务器内部错误',
      message: error.message 
    });
  }
});

// 获取单个日程
expressApp.get('/api/schedules/:id', (req, res) => {
  const schedules = store.get('scheduleList', [])
  const schedule = schedules.find(s => s.id === req.params.id)
  if (!schedule) {
    return res.status(404).json({ error: 'Schedule not found' })
  }
  res.json(schedule)
})

// 检查单个日程是否需要提醒
const checkSingleReminder = (scheduleItem) => {
  const now = new Date()
  const today = new Date(now.getFullYear(), now.getMonth(), now.getDate())
  const tomorrow = new Date(today)
  tomorrow.setDate(tomorrow.getDate() + 1)

  const reminderTime = new Date(scheduleItem.reminder)
  if (reminderTime >= today && reminderTime < tomorrow && !scheduleItem.hasNotified) {
    const job = schedule.scheduleJob(reminderTime, () => {
      showReminderNotification(scheduleItem)
      // 更新存储中的日程状态
      const schedules = store.get('scheduleList', [])
      const updatedSchedules = schedules.map(s =>
        s.id === scheduleItem.id ? { ...s, hasNotified: true } : s
      )
      store.set('scheduleList', updatedSchedules)
      // 取消任务
      job.cancel()
    })
    return job
  }
  return null
}

// 创建新日程
expressApp.post('/api/schedules', (req, res) => {
  const schedules = store.get('scheduleList', [])
  const newSchedule = {
    ...req.body,
    id: Date.now().toString(), // 使用时间戳作为临时ID
    hasNotified: false
  }
  schedules.push(newSchedule)
  store.set('scheduleList', schedules)

  // 判断是否为循环任务
  if (newSchedule.repeatType && newSchedule.repeatType !== 'none') {
    // 只为今天范围内的实例创建提醒
    const today = dayjs().startOf('day')
    const tomorrow = today.add(1, 'day')
    const todayInstances = expandRecurringSchedules([newSchedule], today, tomorrow)
    todayInstances.forEach(instance => {
      if (instance.reminder) {
        checkSingleReminder(instance)
      }
    })
  } else if (newSchedule.reminder) {
    // 非循环任务，直接创建提醒
    checkSingleReminder(newSchedule)
  }
  if (scheduleWindow && scheduleWindow.webContents) {
    scheduleWindow.webContents.send('schedule-updated')
  }
  res.status(201).json(newSchedule)
})

// 更新日程
expressApp.put('/api/schedules/:id', (req, res) => {
  const schedules = store.get('scheduleList', [])
  const index = schedules.findIndex(s => s.id === req.params.id)
  if (index === -1) {
    return res.status(404).json({ error: 'Schedule not found' })
  }

  // 取消原有的提醒任务（如果存在）
  const oldSchedule = schedules[index]
  if (oldSchedule.reminderJob) {
    oldSchedule.reminderJob.cancel()
  }

  // 更新日程
  const updatedSchedule = {
    ...schedules[index],
    ...req.body,
    hasNotified: false // 重置提醒状态
  }
  schedules[index] = updatedSchedule
  store.set('scheduleList', schedules)

  // 如果是今天的日程且有提醒时间，则创建新的提醒任务
  if (updatedSchedule.reminder) {
    const job = checkSingleReminder(updatedSchedule)
    if (job) {
      updatedSchedule.reminderJob = job
      store.set('scheduleList', schedules)
    }
  }

  res.json(updatedSchedule)
})

// 删除日程
expressApp.delete('/api/schedules/:id', (req, res) => {
  const schedules = store.get('scheduleList', [])
  const scheduleToDelete = schedules.find(s => s.id === req.params.id)

  if (!scheduleToDelete) {
    return res.status(404).json({ error: 'Schedule not found' })
  }

  // 取消提醒任务（如果存在）
  if (scheduleToDelete.reminderJob) {
    scheduleToDelete.reminderJob.cancel()
  }

  const filteredSchedules = schedules.filter(s => s.id !== req.params.id)
  store.set('scheduleList', filteredSchedules)
  if (scheduleWindow && scheduleWindow.webContents) {
    scheduleWindow.webContents.send('schedule-updated')
  }
  res.status(204).json({
    id: scheduleToDelete.id
  })
})

// 启动 Express 服务
expressApp.listen(PORT, () => {
  console.log(`Schedule API server running on port ${PORT}`)
})

// 检查今日提醒
const checkTodayReminders = () => {
  const schedules = store.get('scheduleList', [])
  const now = new Date()
  const today = new Date(now.getFullYear(), now.getMonth(), now.getDate())
  const tomorrow = new Date(today)
  tomorrow.setDate(tomorrow.getDate() + 1)

  // 过滤出今天需要提醒的日程
  const todayReminders = expandRecurringSchedules(
    schedules,
    today,
    tomorrow
  ).filter(scheduleItem => {
    if (!scheduleItem.reminder) return false
    const reminderTime = new Date(scheduleItem.reminder)
    return reminderTime >= today && reminderTime < tomorrow && !scheduleItem.hasNotified
  })

  // 为每个提醒创建定时任务
  todayReminders.forEach(scheduleItem => {
    const reminderTime = new Date(scheduleItem.reminder)
    const job = schedule.scheduleJob(reminderTime, () => {
      showReminderNotification(scheduleItem)
      // 更新存储中的日程状态
      const updatedSchedules = schedules.map(s =>
        s.id === scheduleItem.id ? { ...s, hasNotified: true } : s
      )
      store.set('scheduleList', updatedSchedules)
      // 取消任务
      job.cancel()
    })
  })
}

// 显示提醒通知
const showReminderNotification = (schedule) => {
  const notification = new Notification({
    title: `日程提醒 - ${getEventTypeText(schedule.type)}`,
    body: `${schedule.title}\n时间: ${formatTimeRange(schedule.start, schedule.end)}\n${schedule.description || ''}`,
    icon: path.join(process.env.APP_ROOT, 'logo.ico'),
    timeoutType: 'never'
  })

  notification.show()
}

// 获取事件类型文本
const getEventTypeText = (type) => {
  switch (type) {
    case 'important':
      return '重要'
    case 'normal':
      return '日常'
    case 'minor':
      return '次要'
    default:
      return '未知'
  }
}

// 格式化时间范围
const formatTimeRange = (start, end) => {
  const startTime = new Date(start)
  const endTime = new Date(end)
  return `${startTime.toLocaleTimeString()} - ${endTime.toLocaleTimeString()}`
}

const checkTomorrowReminders = () => {
  const schedules = store.get('scheduleList', []);
  const now = new Date();
  const tomorrow = new Date(now.getFullYear(), now.getMonth(), now.getDate() + 1);
  const dayAfterTomorrow = new Date(tomorrow);
  dayAfterTomorrow.setDate(dayAfterTomorrow.getDate() + 1);

  // 过滤出明天需要提醒的日程
  const tomorrowReminders = expandRecurringSchedules(
    schedules,
    tomorrow,
    dayAfterTomorrow
  ).filter(scheduleItem => {
    if (!scheduleItem.reminder) return false;
    const reminderTime = new Date(scheduleItem.reminder);
    return reminderTime >= tomorrow && reminderTime < dayAfterTomorrow && !scheduleItem.hasNotified;
  });

  // 为每个提醒创建定时任务
  tomorrowReminders.forEach(scheduleItem => {
    const reminderTime = new Date(scheduleItem.reminder);
    const job = schedule.scheduleJob(reminderTime, () => {
      showReminderNotification(scheduleItem);
      // 更新存储中的日程状态
      const updatedSchedules = schedules.map(s =>
        s.id === scheduleItem.id ? { ...s, hasNotified: true } : s
      );
      store.set('scheduleList', updatedSchedules);
      // 取消任务
      job.cancel();
    });
  });
};